#include "ModelXml.h"
#include <QDebug>
#include <QFile>

ModelXml* ModelXml::g_ModelXml = nullptr;
ModelXml* ModelXml::GetInstance()
{
    if (!g_ModelXml)
        g_ModelXml = new ModelXml;
    return g_ModelXml;
}

ModelXml::ModelXml()
{
    m_deviceNumber = 0;
}

void ModelXml::AddProject(stProject projectName)
{
    m_project = projectName;
    m_collectChannel.clear();
    m_deviceNumber = 0;
}

stProject& ModelXml::GetProject()
{
    return m_project;
}

int ModelXml::AddCollectChannel(stCollectChannel channel)
{
    m_collectChannel[channel.id] = channel;
    return 1;
}

void ModelXml::DelCollectChannel(int channelID)
{
    m_collectChannel.erase(channelID);
    m_collectDevice.erase(channelID);
}

std::map<int, stCollectChannel> ModelXml::GetCollectChannel()
{
    return m_collectChannel;
}

std::map<int, stCollectChannel>* ModelXml::GetCollectChannelPointer()
{
    return &m_collectChannel;
}

int ModelXml::AddCollectDevice(int parentID, stCollecDevice device)
{
    std::map<int, std::map<int, stCollecDevice>>::iterator it = m_collectDevice.find(parentID);
    if (it != m_collectDevice.end()) {
        it->second.insert({ device.id, device });
    } else {
        std::map<int, stCollecDevice> mapDevice;
        mapDevice[device.id] = device;
        m_collectDevice[parentID] = mapDevice;
    }

    return 1;
}

std::map<int, stCollecDevice> ModelXml::GetCollectDevice(int channelID)
{
    std::map<int, stCollecDevice> result;
    if (m_collectDevice.find(channelID) != m_collectDevice.end()) {
        result = m_collectDevice.find(channelID)->second;
    }
    return result;
}

std::map<int, std::map<int, stCollecDevice>>* ModelXml::GetAllDevice()
{
    return &m_collectDevice;
}

stCollecDevice* ModelXml::GetCollectDevicePointer(int channelID, int deviceID)
{
    //std::map<int,std::map<int ,stCollecDevice> > m_collectDevice;
    // stCollecDevice *res = new stCollecDevice;
    //stCollecDevice  *stResult = nullptr;
    if (m_collectDevice.find(channelID) != m_collectDevice.end()) {
        std::map<int, stCollecDevice>::iterator itDevice = m_collectDevice.find(channelID)->second.find(deviceID);
        if (itDevice != m_collectDevice.find(channelID)->second.end()) {
            return &itDevice->second;
        }
    }
    return nullptr;
}

stCollecDevice ModelXml::GetCollectDevice(int channelID, int deviceID)
{
    stCollecDevice res;
    if (m_collectDevice.find(channelID) != m_collectDevice.end()) {
        std::map<int, stCollecDevice>::iterator itDevice = m_collectDevice.find(channelID)->second.find(deviceID);
        if (itDevice != m_collectDevice.find(channelID)->second.end()) {
            res = itDevice->second;
            qDebug() << "child name1 = " << itDevice->second.pointTable_node.child("tag").attribute("name").value();
        }
    }

    return res;
}

int ModelXml::GetMaxCollectChannelID()
{
    if (m_collectChannel.size() == 0)
        return 0;
    return m_collectChannel.cend()->first;
}

bool ModelXml::OpenProjectFile(std::string pathXml)
{

    if (!m_doc.load_file(pathXml.c_str())) {
        qDebug() << "open file failed :" << pathXml.c_str();
        return false;
    }
    xml_node project_node = m_doc.root().child("project");
    if (project_node == nullptr) {
        qDebug() << "load file failed : no file project node :" << pathXml.c_str();
        return false;
    }
    m_project.createTime = project_node.attribute("createTime").value();
    m_project.desc = project_node.attribute("desc").value();
    m_project.name = project_node.attribute("name").value();
    m_project.path = project_node.attribute("path").value();
    m_project.modiTime = project_node.attribute("modiTime").value();

    //采集通道
    xml_node channel_node = project_node.child("collect").first_child();
    while (channel_node) {
        stCollectChannel channel;
        channel.id = channel_node.attribute("id").as_int();
        channel.name = channel_node.attribute("name").value();
        channel.desc = channel_node.attribute("desc").value();
        channel.protoName = channel_node.attribute("protoName").value();
        channel.protocate = channel_node.attribute("protocate").value();
        channel.portType = (stCollectChannel::ChannelPortType)channel_node.attribute("portType").as_int();
        channel.reserve = channel_node.attribute("reserve").value();
        channel.serialport.name = channel_node.attribute("comName").value();
        channel.serialport.baudRate = channel_node.attribute("baudRate").value();
        channel.serialport.checkBit = channel_node.attribute("checkBit").value();
        channel.serialport.dataBit = channel_node.attribute("dataBit").value();
        channel.serialport.stopBit = channel_node.attribute("stopBit").value();
        m_collectChannel[channel.id] = channel;

        xml_node device_node = channel_node.child("device");
        while (device_node) {
            stCollecDevice collectDevice;
            collectDevice.id = device_node.attribute("id").as_int();
            collectDevice.desc = device_node.attribute("desc").value();
            collectDevice.devAddr = device_node.attribute("devAddr").value();
            collectDevice.name = device_node.attribute("name").value();
            collectDevice.isDisable = device_node.attribute("isDisable").as_bool();
            collectDevice.periodTime = device_node.attribute("periodTime").value();
            collectDevice.InterfaceType = (stCollecDevice::Intarface_Type)device_node.attribute("InterfaceType").as_int();
            collectDevice.tcpClient.ipaddrA = device_node.attribute("tcpclientIpaddrA").value();
            collectDevice.tcpClient.ipaddrB = device_node.attribute("tcpclientIpaddrB").value();
            collectDevice.tcpClient.portA = device_node.attribute("tcpclientPortA").value();
            collectDevice.tcpClient.portB = device_node.attribute("tcpclientPortB").value();

            collectDevice.tcpServer.ipaddr = device_node.attribute("tcpServerIpaddr").value();
            collectDevice.tcpServer.port = device_node.attribute("tcpServerPort").value();

            collectDevice.udp.localIpaddr = device_node.attribute("updSrcIpaddr").value();
            collectDevice.udp.localPort = device_node.attribute("updSrcPort").value();
            collectDevice.udp.remoteIpaddr = device_node.attribute("updDestIpaddr").value();
            collectDevice.udp.remotePort = device_node.attribute("updDestPort").value();

            device_node.text();
            xml_node param_node = device_node.child("params").first_child();
            while (param_node) {
                stPrivateParam param;
                param.id = param_node.attribute("id").as_int();
                param.name = param_node.attribute("name").value();
                param.desc = param_node.attribute("desc").value();
                param.value = param_node.attribute("value").value();
                collectDevice.params.push_back(param);
                param_node = param_node.next_sibling();
            }
            //点表
            //xml_node
            collectDevice.pointTable_node = device_node.child("points");
            std::map<int, std::map<int, stCollecDevice>>::iterator it = m_collectDevice.find(channel.id);
            if (it != m_collectDevice.end()) {
                it->second.insert({ collectDevice.id, collectDevice });
            } else {
                std::map<int, stCollecDevice> mapDevice;
                mapDevice.insert({ collectDevice.id, collectDevice });
                m_collectDevice.insert({ channel.id, mapDevice });
            }
            device_node = device_node.next_sibling();
        }
        channel_node = channel_node.next_sibling();
    }

    xml_node update_node = project_node.child("update").first_child();
    while (update_node) {
        stUpdateChannel updateChannel;
        updateChannel.id = update_node.attribute("id").as_int();
        updateChannel.name = update_node.attribute("name").value();
        updateChannel.desc = update_node.attribute("desc").value();
        updateChannel.protoCate = update_node.attribute("protoCate").value();
        updateChannel.protoName = update_node.attribute("protoName").value();

        updateChannel.isDisable = update_node.attribute("isDisable").as_int();
        updateChannel.intarfaceType = (stUpdateChannel::Intarface_Type)update_node.attribute("intarfaceType").as_int();
        updateChannel.devAddr = update_node.attribute("devAddr").value();
        updateChannel.periodTime = update_node.attribute("periodTime").value();

        updateChannel.tcpClient.ipaddrA = update_node.attribute("tcpclientIpaddrA").value();
        updateChannel.tcpClient.ipaddrB = update_node.attribute("tcpclientIpaddrB").value();
        updateChannel.tcpClient.portA = update_node.attribute("tcpclientPortA").value();
        updateChannel.tcpClient.portB = update_node.attribute("tcpclientPortB").value();

        updateChannel.tcpServer.ipaddr = update_node.attribute("tcpServerIpaddr").value();
        updateChannel.tcpServer.port = update_node.attribute("tcpServerPort").value();

        updateChannel.udp.localIpaddr = update_node.attribute("updSrcIpaddr").value();
        updateChannel.udp.localPort = update_node.attribute("updSrcPort").value();
        updateChannel.udp.remoteIpaddr = update_node.attribute("updDestIpaddr").value();
        updateChannel.udp.remotePort = update_node.attribute("updDestPort").value();

        xml_node param_node = update_node.child("params").first_child();
        while (param_node) {
            stPrivateParam param;
            param.id = param_node.attribute("id").as_int();
            param.name = param_node.attribute("name").value();
            param.desc = param_node.attribute("desc").value();
            param.value = param_node.attribute("value").value();
            updateChannel.params.push_back(param);

            param_node = param_node.next_sibling();
        }
        m_updateChannel[updateChannel.id] = updateChannel;
        update_node = update_node.next_sibling();
    }
    return true;
}

bool ModelXml::CloseProject()
{
    m_collectChannel.clear(); //采集通道
    m_collectDevice.clear(); //所属通道ID,设备ID,设备信息
    m_updateChannel.clear();
    return true;
}

bool ModelXml::DeleteProject()
{
    QFile::remove((m_project.path + "/" + m_project.name).c_str());
    m_collectChannel.clear(); //采集通道
    m_collectDevice.clear(); //所属通道ID,设备ID,设备信息
    m_updateChannel.clear();
    return true;
}

stCollectChannel ModelXml::GetCollectChannel(int channelID)
{
    stCollectChannel stChannel;
    std::map<int, stCollectChannel>::iterator it = m_collectChannel.find(channelID);
    if (it != m_collectChannel.end()) {
        stChannel = it->second;
    }
    return stChannel;
}

void ModelXml::ModiCollectChannel(stCollectChannel st)
{
    stCollectChannel stChannel;
    std::map<int, stCollectChannel>::iterator it = m_collectChannel.find(st.id);
    if (it != m_collectChannel.end()) {
        m_collectChannel[st.id] = st;
    }
}

int ModelXml::GetMaxCollectDeviceID(int channelID)
{
    int id = 0;
    std::map<int, std::map<int, stCollecDevice>>::iterator it = m_collectDevice.find(channelID);
    if (it != m_collectDevice.end()) {

        if (it->second.size() <= 0)
            return 0;
        id = (--it->second.end())->first;
    }
    return id;
}

bool ModelXml::ModiCollectDevice(int channelID, stCollecDevice dev)
{
    std::map<int, std::map<int, stCollecDevice>>::iterator itChannel = m_collectDevice.find(channelID);
    if (itChannel != m_collectDevice.end()) {
        std::map<int, stCollecDevice>::iterator devIt = itChannel->second.find(dev.id);
        if (devIt != itChannel->second.end()) {
            devIt->second.name = dev.name;
            devIt->second.desc = dev.desc;
            devIt->second.devAddr = dev.devAddr;
            devIt->second.isDisable = dev.isDisable;
            devIt->second.params = dev.params;
            devIt->second.periodTime = dev.periodTime;
            devIt->second.tcpClient = dev.tcpClient;
            devIt->second.udp = dev.udp;
            devIt->second.tcpServer = dev.tcpServer;
            devIt->second.InterfaceType = dev.InterfaceType;
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

bool ModelXml::DelCollectDevice(int channelID, int devID)
{
    std::map<int, std::map<int, stCollecDevice>>::iterator itChannel = m_collectDevice.find(channelID);
    if (itChannel != m_collectDevice.end()) {
        std::map<int, stCollecDevice>::iterator itDev = itChannel->second.find(devID);
        if (itDev != itChannel->second.end()) {
            itChannel->second.erase(itDev->first);
            return true;
        }

    } else {
        return false;
    }
}

int ModelXml::GetMaxUpdateChannelID()
{
    if (m_updateChannel.size() == 0)
        return 0;

    return (--m_updateChannel.end())->first;
}

void ModelXml::AddUpdateChannel(stUpdateChannel stChannel)
{
    m_updateChannel[stChannel.id] = stChannel;
}

bool ModelXml::DelUpdateChannel(int channelID)
{
    m_updateChannel.erase(channelID);
    return true;
}

std::map<int, stUpdateChannel> ModelXml::GetUpdateChannelList()
{
    return m_updateChannel;
}

stUpdateChannel* ModelXml::GetUpdateChannelInfoPointer(int channelID)
{

    if (m_updateChannel.find(channelID) != m_updateChannel.end()) {
        return &m_updateChannel.find(channelID)->second;
    }
    return nullptr;
}

stUpdateChannel ModelXml::GetUpdateChannelInfo(int channelID)
{
    stUpdateChannel res;
    if (m_updateChannel.find(channelID) != m_updateChannel.end()) {
        res = m_updateChannel[channelID];
    }
    return res;
}

bool ModelXml::SaveXml()
{
    pugi::xml_document doc;
    pugi::xml_node declaration = doc.prepend_child(pugi::node_declaration);
    declaration.append_attribute("version") = "1.0";
    declaration.append_attribute("encoding") = "UTF-8";

    xml_node projectNode = doc.append_child("project");
    projectNode.append_attribute("name") = m_project.name.c_str();
    projectNode.append_attribute("desc") = m_project.desc.c_str();
    projectNode.append_attribute("path") = m_project.path.c_str();
    projectNode.append_attribute("createTime") = m_project.createTime.c_str();
    projectNode.append_attribute("modiTime") = m_project.modiTime.c_str();

    xml_node collect_node = projectNode.append_child("collect");
    std::map<int, stCollectChannel>::iterator itCollectChannel = m_collectChannel.begin();
    for (; itCollectChannel != m_collectChannel.end(); itCollectChannel++) {
        xml_node collectChannel_node = collect_node.append_child("channel");
        collectChannel_node.append_attribute("id") = itCollectChannel->second.id;
        collectChannel_node.append_attribute("name") = itCollectChannel->second.name.c_str();
        collectChannel_node.append_attribute("desc") = itCollectChannel->second.desc.c_str();
        collectChannel_node.append_attribute("protoName") = itCollectChannel->second.protoName.c_str();
        collectChannel_node.append_attribute("protocate") = itCollectChannel->second.protocate.c_str();
        collectChannel_node.append_attribute("portType") = itCollectChannel->second.portType;
        collectChannel_node.append_attribute("reserve") = itCollectChannel->second.reserve.c_str();
        collectChannel_node.append_attribute("comName") = itCollectChannel->second.serialport.name.c_str();
        collectChannel_node.append_attribute("baudRate") = itCollectChannel->second.serialport.baudRate.c_str();
        collectChannel_node.append_attribute("dataBit") = itCollectChannel->second.serialport.dataBit.c_str();
        collectChannel_node.append_attribute("checkBit") = itCollectChannel->second.serialport.checkBit.c_str();
        collectChannel_node.append_attribute("stopBit") = itCollectChannel->second.serialport.stopBit.c_str();

        std::map<int, std::map<int, stCollecDevice>>::iterator itDevice = m_collectDevice.find(itCollectChannel->first);
        if (itDevice != m_collectDevice.end()) {
            for (std::map<int, stCollecDevice>::iterator it = itDevice->second.begin(); it != itDevice->second.end(); it++) {
                xml_node dev_node = collectChannel_node.append_child("device");
                dev_node.append_attribute("id") = it->second.id;
                dev_node.append_attribute("name") = it->second.name.c_str();
                dev_node.append_attribute("desc") = it->second.desc.c_str();
                dev_node.append_attribute("isDisable") = it->second.isDisable;
                dev_node.append_attribute("devAddr") = it->second.devAddr.c_str();
                dev_node.append_attribute("periodTime") = it->second.periodTime.c_str();
                dev_node.append_attribute("InterfaceType") = it->second.InterfaceType;
                dev_node.append_attribute("tcpclientIpaddrA") = it->second.tcpClient.ipaddrA.c_str();
                dev_node.append_attribute("tcpclientIpaddrB") = it->second.tcpClient.ipaddrB.c_str();
                dev_node.append_attribute("tcpclientPortA") = it->second.tcpClient.portA.c_str();
                dev_node.append_attribute("tcpclientPortB") = it->second.tcpClient.portB.c_str();
                dev_node.append_attribute("tcpServerIpaddr") = it->second.tcpServer.ipaddr.c_str();
                dev_node.append_attribute("tcpServerPort") = it->second.tcpServer.port.c_str();
                dev_node.append_attribute("updSrcPort") = it->second.udp.localPort.c_str();
                dev_node.append_attribute("updSrcIpaddr") = it->second.udp.localIpaddr.c_str();
                dev_node.append_attribute("updDestPort") = it->second.udp.remotePort.c_str();
                dev_node.append_attribute("updDestIpaddr") = it->second.udp.remoteIpaddr.c_str();
                xml_node params_node = dev_node.append_child("params");
                for (int var = 0; var < it->second.params.size(); ++var) {
                    stPrivateParam param = it->second.params.at(var);
                    xml_node param_node = params_node.append_child("param");
                    param_node.append_attribute("id") = param.id;
                    param_node.append_attribute("desc") = param.desc.c_str();
                    param_node.append_attribute("name") = param.name.c_str();
                    param_node.append_attribute("value") = param.value.c_str();
                }
                xml_node node = it->second.pointTable_node;
                std::string test = node.attribute("a").value();
                dev_node.append_copy(it->second.pointTable_node);
            }
        }
    }
    xml_node update_node = projectNode.append_child("update");
    for (std::map<int, stUpdateChannel>::iterator it = m_updateChannel.begin(); it != m_updateChannel.end(); it++) {
        xml_node dev_node = update_node.append_child("device");
        stUpdateChannel stUpdate = it->second;
        dev_node.append_attribute("id") = stUpdate.id;
        dev_node.append_attribute("name") = stUpdate.name.c_str();
        dev_node.append_attribute("desc") = stUpdate.desc.c_str();
        dev_node.append_attribute("protoCate") = stUpdate.protoCate.c_str();
        dev_node.append_attribute("protoName") = stUpdate.protoName.c_str();
        dev_node.append_attribute("isDisable") = stUpdate.isDisable;
        dev_node.append_attribute("intarfaceType") = stUpdate.intarfaceType;
        dev_node.append_attribute("devAddr") = stUpdate.devAddr.c_str();
        dev_node.append_attribute("periodTime") = stUpdate.periodTime.c_str();
        dev_node.append_attribute("tcpclientIpaddrA") = stUpdate.tcpClient.ipaddrA.c_str();
        dev_node.append_attribute("tcpclientIpaddrB") = stUpdate.tcpClient.ipaddrB.c_str();
        dev_node.append_attribute("tcpclientPortA") = stUpdate.tcpClient.portA.c_str();
        dev_node.append_attribute("tcpclientPortB") = stUpdate.tcpClient.portB.c_str();

        dev_node.append_attribute("tcpServerIpaddr") = stUpdate.tcpServer.ipaddr.c_str();
        dev_node.append_attribute("tcpServerPort") = stUpdate.tcpServer.port.c_str();

        dev_node.append_attribute("updSrcIpaddr") = stUpdate.udp.localIpaddr.c_str();
        dev_node.append_attribute("updSrcPort") = stUpdate.udp.localPort.c_str();
        dev_node.append_attribute("updDestIpaddr") = stUpdate.udp.remoteIpaddr.c_str();
        dev_node.append_attribute("updDestPort") = stUpdate.udp.remotePort.c_str();

        dev_node.append_attribute("comName") = stUpdate.serialport.name.c_str();
        dev_node.append_attribute("baudRate") = stUpdate.serialport.baudRate.c_str();
        dev_node.append_attribute("dataBit") = stUpdate.serialport.dataBit.c_str();
        dev_node.append_attribute("checkBit") = stUpdate.serialport.checkBit.c_str();
        dev_node.append_attribute("stopBit") = stUpdate.serialport.stopBit.c_str();
        xml_node params_node = dev_node.append_child("params");
        for (int var = 0; var < stUpdate.params.size(); ++var) {
            stPrivateParam param = stUpdate.params.at(var);
            xml_node param_node = params_node.append_child("param");
            param_node.append_attribute("id") = param.id;
            param_node.append_attribute("desc") = param.desc.c_str();
            param_node.append_attribute("name") = param.name.c_str();
            param_node.append_attribute("value") = param.value.c_str();
        }
    }
    return doc.save_file((m_project.path + "/" + m_project.name + ".pxm").c_str()); //xml_encoding::encoding_utf8);
}
